#pragma once

class CIdentifiers
{
public:
	static bool AssertValidIdentifier(const char *szIdentifier)
	{
		if(*szIdentifier == '_' || IsAlphabetic(*szIdentifier))
		{
			while(char c = *++szIdentifier)
			{
				if(!IsIdentifierChar(c))
					THROW(IsPrint(c) ? "Illegal char in identifier '%c'" : "Illegal char in identifier \\x%X", c);
			}
		}
		else THROW("Identifier '%s' must begin with a letter or underscore", szIdentifier);
		return true;
	}
	static bool IsValidIdentifier(const char *szIdentifier)
	{
		if(*szIdentifier == '_' || IsAlphabetic(*szIdentifier))
		{
			while(char c = *++szIdentifier)
			{
				if(!IsIdentifierChar(c))
					return false;
			}
		}
		else return false;
		return true;
	}
};

class CIdentifier
{
protected:
	//char			m_szName[MAX_IDENTIFIER_NAME+4]; // die
	char		*	m_szName;
	size_t			m_nLength;
	DWORD			m_dwHash;

	CIdentifier(const char *szName)
	{
		if(szName && *szName && CIdentifiers::AssertValidIdentifier(szName))
		{
			m_nLength = strlen(szName);
			m_szName = new char[m_nLength+1];
			szncpy(m_szName, szName, m_nLength+1);
			switch(SCRambl.Config.Parser.GetCaseConversion())
			{
			case CASE_CONVERT_UPPER: StringToUpper(m_szName, m_nLength); break;
			case CASE_CONVERT_LOWER: StringToLower(m_szName, m_nLength); break;
			}
			m_dwHash = GenerateHash(m_szName);
		}
		else
		{
			m_szName = nullptr;
			m_dwHash = 0xFFFFFFFF;
		}
	}
	~CIdentifier()
	{
		if(m_szName) delete[] m_szName;
	}

	inline bool IsEqual(const CIdentifier &v) const					{return GetHash() == v.GetHash() && GetNameLength() == v.GetNameLength();}
	
public:
	inline size_t			GetNameLength()	 const					{return m_nLength;}
	inline const char	*	GetName() const							{return m_szName;}
	inline void				GetName(char *szBuf) const				{szncpy(szBuf, m_szName, m_nLength+1);}
	inline DWORD			GetHash() const							{return m_dwHash;}

	inline bool IsNamed(const char *szName) const					{return strncmp(szName, m_szName, m_nLength) == 0;}
	inline bool IsNamed(const char *szName, DWORD dwHash) const		{return dwHash == m_dwHash && IsNamed(szName);}
	inline bool IsNamed(const CIdentifier &v) const					{return GetHash() == v.GetHash() && GetNameLength() == v.GetNameLength();}
};